
type SokcetEventFn<T> = (ev: T) => void;
type onFn = (data: unknown) => void;
type onFnMap = {
  [key: string]: onFn
};
interface Msg {
  _type: string, 
  data: any
}
export class FishSocket {
  socket: WebSocket | null;
  onFns: onFnMap

  constructor(url: string) {
    this.socket = new WebSocket(url);  
    this.onFns = {};  
    this.#message();
  }

  sendText(_type: string, obj: any) {
    this.socket?.send(JSON.stringify({
      _type,
      data: obj
    }));
  }

  sendBin(stream: Blob) {
    this.socket?.send(stream);
  }

  onOpen(fn: SokcetEventFn<Event>) {
    this.socket?.addEventListener("open", fn);
  }

  #message() {
    this.socket?.addEventListener("message", e => {
      let msg: Msg = JSON.parse(e.data);
      this.onFns[msg._type] && this.onFns[msg._type](msg.data as unknown);
    });
  }

  on(type: string, fn: onFn) {
    this.onFns[type] = fn;
  }

  onClose(fn: SokcetEventFn<CloseEvent>) {
    this.socket?.addEventListener("close", fn);
  }

  close() {
    this.socket?.close();
    this.socket = null;
  }
}